package com.bcbim.api_web.pipeManagement.controller;

import com.alibaba.fastjson.JSONArray;
import com.bcbim.api_web.sys.interceptor.TranslateHandle;
import com.bcbim.authentication_interface.util.AuthUtil;
import com.bcbim.common.response.annotation.Translate;
import com.bcbim.api_web.sys.redis.MyRedisService;
import com.bcbim.common.response.vo.ReturnMsg;
import com.bcbim.common.response.vo.ReturnPageMsg;
import com.bcbim.common.sys.Constant;
import com.bcbim.common.sys.ParamException;
import com.bcbim.common.util.LngLonUtil;
import com.bcbim.common.util.MyListUtil;
import com.bcbim.common.util.ParamCheck;
import com.bcbim.smart_water_interface.file.service.FileService;
import com.bcbim.smart_water_interface.file.vo.FileVO;
import com.bcbim.smart_water_interface.line.service.PipelineLineService;
import com.bcbim.smart_water_interface.pipeManagement.dto.AddLineInSetDTO;
import com.bcbim.smart_water_interface.pipeManagement.dto.AddPointSetDTO;
import com.bcbim.smart_water_interface.pipeManagement.dto.PipelineFrameSelectInput;
import com.bcbim.smart_water_interface.pipeManagement.service.PipeManagementService;
import com.bcbim.smart_water_interface.pipeManagement.vo.*;
import com.bcbim.smart_water_interface.pipeline.VO.PipelineLineVO;
import com.bcbim.smart_water_interface.pipeline.VO.PipelinePointVO;
import com.bcbim.smart_water_interface.point.service.PipelinePointService;
import com.bcbim.smart_water_interface.road.vo.RoadPullVO;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.gavaghan.geodesy.Ellipsoid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description: 管网信息管理controller
 * @Author haoshuai
 * @Date 2021/8/19
 * @Version V1.0
 **/
@RestController
@RequestMapping("/pipeManagement")
public class PipeManagementController {

    @Reference(protocol = "dubbo", group = "pipeManagement", version = "1.0.0")
    private PipeManagementService pipeManagementService;
    @Reference(protocol = "dubbo", group = "pipelinePoint", version = "1.0.0")
    private PipelinePointService pipelinePointServiceImpl;
    @Reference(protocol = "dubbo", group = "pipelineLine", version = "1.0.0")
    private PipelineLineService pipelineLineServiceImpl;
    @Reference(protocol = "dubbo", group = "pipeFile", version = "1.0.0")
    private FileService fileServiceImpl;

    @Autowired
    private MyRedisService myReidsService;

    /**
     * 管点检索加入选集
     *
     * @param params 前端传入管点加入选集参数
     * @param: code 管线编号
     * @param: feature 特征
     * @param: attachmen 附属
     * @param: startHigh 起始高程
     * @param: endHigh 结束高程
     * @param: uses 用途
     * @param: startBury 开始井底深
     * @param: endBury 结束井底深
     * @param: roadId 道路id
     * @param: pageNum 页码
     * @param: pageSize 每页记录数
     * @return: com.bcbim.common.response.vo.ReturnPageMsg
     * @author wxc
     * @date 2021/8/25  11:11
     */
    @PostMapping("/insertPointInSet")
    public ReturnMsg insertPointInSet(AddPointSetDTO params) {
        // 查询管点数据
        List<PipeListVO> listPointVO = pipeManagementService.pointNoPaging(params);
        if(ObjectUtils.isEmpty(listPointVO)){
            return ReturnMsg.consFail("筛选结果为空，加入集选失败！");
        }
        // 取redis中数据集合
        String token = AuthUtil.getPointToken();
        if (StringUtils.isEmpty(token)) {
            return ReturnMsg.consFail("查询失败，请重新登录。");
        }
        JSONArray jsonArray = (JSONArray) myReidsService.get(token);
        List<PipeListVO> cacheList = jsonArray == null ? null : jsonArray.toJavaList(PipeListVO.class);

        // 写入集合
        // 缓存中数据为null，则直接存入缓存
        // 缓存中存在数据，将数据去重后重新写入redis
        List<PipeListVO> list;
        if (ObjectUtils.isEmpty(cacheList)) {
            list = listPointVO;
        } else {
            list = MyListUtil.removeAll(listPointVO, cacheList);
            list.addAll(cacheList);
        }
        // 写入redis
        myReidsService.set(token, list, Constant.PERMISSION_EXPIRATION_TIME);

        return ReturnMsg.consSuccess(Constant.SAVE_SUCCESS);
    }

    /**
     * 管线检索加入选集
     *
     * @Param: code 管线编号
     * @Param: roadId 道路id
     * @Param: uses 用途(码值)
     * @Param: pipeDiameterMin 管径范围(最小)
     * @Param: pipeDiameterMax 管径范围(最大)
     * @Param: buryType 埋设方式(码值)
     * @Param: material 材质(码值)
     * @Param: pageNum 页码
     * @Param: pageSize 每页记录数
     * @Return: ReturnPageMsg
     * @Author: haoshuai
     * @Date: 2021/8/19
     */
    @PostMapping("/insertLineInSet")
    public ReturnMsg insertLineInSet(AddLineInSetDTO params) {
        // 查询管线数据
        List<PipeListVO> listLineVO = pipeManagementService.listLineNoPaging(params);
        if(ObjectUtils.isEmpty(listLineVO)){
            return ReturnMsg.consFail("筛选结果为空，加入集选失败！");
        }

        // 取redis中管线数据集合
        String lineToken = AuthUtil.getLineToken();
        if (StringUtils.isEmpty(lineToken)) {
            return ReturnMsg.consFail("查询失败，请重新登录。");
        }
        JSONArray lineJsonArray = (JSONArray) myReidsService.get(lineToken);
        List<PipeListVO> cacheListLine = null == lineJsonArray ? null : lineJsonArray.toJavaList(PipeListVO.class);

        // 写入集合
        // 若缓存中数据集合不为空, 则将查询集合和缓存集合去重后合并
        // 若缓存中数据集合为空, 则将查询结合作为结果集合
        List<PipeListVO> list;
        if (CollectionUtils.isNotEmpty(cacheListLine)) {
            list = MyListUtil.removeAll(listLineVO, cacheListLine);
            list.addAll(cacheListLine);
        } else {
            list = listLineVO;
        }

        // 写入redis
        myReidsService.set(lineToken, list, Constant.PERMISSION_EXPIRATION_TIME);
        return ReturnMsg.consSuccess(Constant.SAVE_SUCCESS);
    }


    /**
     * 查看全部 管点 管线 集选
     *
     * @param pageNum  当前页码
     * @param pageSize 每页显示条数
     * @param type     管点1 管线2  类型
     * @return com.bcbim.common.response.vo.ReturnPageMsg
     * @author wxc
     * @date 2021/8/25  15:09
     */
    @PostMapping("/getPipeList")
    public ReturnPageMsg getPipeList(@RequestParam(required = true) Integer pageNum,
                                     @RequestParam(required = true) Integer pageSize,
                                     @RequestParam(required = true) String type) {
        // 参数校验
        try {
            ParamCheck.pageNumCheck(pageNum, pageSize);
            // 校验 管点1 管线2 全部3 类型
            ParamCheck.stringNotEmptyRegexpCheck(type, "^[1|2|3]$");
        } catch (ParamException e) {
            return ReturnPageMsg.consFail(ParamException.PARAMETER_ERROR);
        }
        JSONArray jsonArray = new JSONArray();
        // 通过类型获取集合列表----空:全部集选 1:管点  2:管线  3:全部
        if ("3".equals(type)) {
            JSONArray pointList = (JSONArray) myReidsService.get(AuthUtil.getPointToken());
            JSONArray lineList = (JSONArray) myReidsService.get(AuthUtil.getLineToken());
            if (ObjectUtils.isNotEmpty(pointList)) {
                jsonArray.addAll(pointList);
            }
            if (ObjectUtils.isNotEmpty(lineList)) {
                jsonArray.addAll(lineList);
            }
        } else if ("1".equals(type)) {
            jsonArray = (JSONArray) myReidsService.get(AuthUtil.getPointToken());
        } else if ("2".equals(type)) {
            jsonArray = (JSONArray) myReidsService.get(AuthUtil.getLineToken());
        }

        if (ObjectUtils.isEmpty(jsonArray)) {
            return ReturnPageMsg.consSuccess(0, new ArrayList<>());
        }
        List<PipeListVO> list = jsonArray.toJavaList(PipeListVO.class);
        List<?> paging = paging(list, pageNum, pageSize);
        return ReturnPageMsg.consSuccess(list.size(), paging);
    }

    /**
     * 删除管点管线集选列表数据
     *
     * @param id   需要删除的id
     * @param type 数据中的类型
     * @return com.bcbim.common.response.vo.ReturnPageMsg
     * @author wxc
     * @date 2021/8/25  16:18
     */
    @PostMapping("/deletePipeline")
    public ReturnMsg delete(String id, String type) {
        // 参数校验
        try {
            // 校验管点数据类型正则表达式
            String regExp = "^[" + Constant.PIPELINE_POINT + "|" + Constant.PIPELINE_LINE + "]$";
            ParamCheck.stringNotEmptyRegexpCheck(type, regExp);
            ParamCheck.idCheck(id);
        } catch (ParamException e) {
            return ReturnMsg.consFail(ParamException.PARAMETER_ERROR);
        }
        // 类型是管点的时候，获取管管点数据进行操作
        if (Objects.equals(Constant.PIPELINE_POINT, type)) {
            String pointToken = AuthUtil.getPointToken();
            JSONArray jsonArray = (JSONArray) myReidsService.get(pointToken);
            if (ObjectUtils.isEmpty(jsonArray)) {
                return ReturnMsg.consFail("集选数据为空，删除失败！");
            }
            // 将删除的id过滤掉
            List<PipePointListVO> pointList = jsonArray.toJavaList(PipePointListVO.class);
            List<PipePointListVO> collect = pointList.stream().filter(obj -> !obj.getId().equals(id)).collect(Collectors.toList());
            // 清空redis中的数据后，重新将筛选后的数据加入reids中
            myReidsService.delete(pointToken);
            myReidsService.set(pointToken, collect, Constant.PERMISSION_EXPIRATION_TIME);
        }
        // 类型是管线的时候的操作
        if (Objects.equals(Constant.PIPELINE_LINE, type)) {
            String lineToken = AuthUtil.getLineToken();
            JSONArray jsonArray = (JSONArray) myReidsService.get(lineToken);
            if (ObjectUtils.isEmpty(jsonArray)) {
                return ReturnMsg.consFail("集选数据为空，删除失败！");
            }
            // 将删除的id过滤掉
            List<PipeLineListVO> pointList = jsonArray.toJavaList(PipeLineListVO.class);
            List<PipeLineListVO> collect = pointList.stream().filter(obj -> !obj.getId().equals(id)).collect(Collectors.toList());
            // 清空redis中的数据后，重新将筛选后的数据加入reids中
            myReidsService.delete(lineToken);
            myReidsService.set(lineToken, collect, Constant.PERMISSION_EXPIRATION_TIME);
        }
        return ReturnMsg.consSuccess(Constant.SAVE_SUCCESS);
    }

    /**
     * 获取道路下拉列表
     *
     * @return com.bcbim.common.response.vo.ReturnMsg
     * @author wxc
     * @date 2021/8/13  11:25
     */
    @PostMapping("/getRoadPull")
    public ReturnMsg getRoadPull() {
        List<RoadPullVO> roadList = pipeManagementService.getRoadPull();
        return ReturnMsg.consSuccess(roadList);
    }

    /**
     * 获取管网数据详情 TODO 修改
     *
     * @param id   数据id
     * @param type 数据类型
     * @return com.bcbim.common.response.vo.ReturnMsg
     * @author wxc
     * @date 2021/8/25  16:47
     */
    @Translate
    @PostMapping("/getPipeInfo")
    public ReturnMsg getPipeInfo(String id, String type) {
        // 参数校验
        String regExp = "^[" + Constant.PIPELINE_POINT + "|" + Constant.PIPELINE_LINE + "]$";// 校验管点数据类型正则表达式
        try {
            ParamCheck.idCheck(id);
            ParamCheck.stringNotEmptyRegexpCheck(type, regExp);
        } catch (ParamException e) {
            return ReturnMsg.consFail(ParamException.PARAMETER_ERROR);
        }
        PipelinePointVO pipelinePointVO = null;
        PipelineLineVO pipelineLineVO = null;
        String fileURL = Constant.PIPE_DRAWING_URL + File.separator;
        //定义管点和管线对象
        switch (type) {
            case Constant.PIPELINE_POINT: //  获取管点详情
                pipelinePointVO = pipelinePointServiceImpl.getPipelinePoint(id);
                List<FileVO> pointFile = fileServiceImpl.getFileByPointId(Lists.newArrayList(id));
                if (ObjectUtils.isNotEmpty(pointFile)) {
                    pipelinePointVO.setDrawing(fileURL + pointFile.get(0).getKeepName());
                }
                break;
            case Constant.PIPELINE_LINE://  获取管线详情
                pipelineLineVO = pipelineLineServiceImpl.getPipelineLine(id);
                // 如果起始点终止点的坐标都不为空，计算长度distance
                if (ObjectUtils.isNotEmpty(pipelineLineVO.getStartPointLatitude()) && ObjectUtils.isNotEmpty(pipelineLineVO.getStartPointLongitude())
                        && ObjectUtils.isNotEmpty(pipelineLineVO.getEndPointLatitude()) && ObjectUtils.isNotEmpty(pipelineLineVO.getEndPointLongitude())) {
                    double distance = LngLonUtil.getDistanceMeter(Double.parseDouble(pipelineLineVO.getStartPointLatitude()), Double.parseDouble(pipelineLineVO.getStartPointLongitude()),
                            Double.parseDouble(pipelineLineVO.getEndPointLatitude()), Double.parseDouble(pipelineLineVO.getEndPointLongitude()), Ellipsoid.WGS84);
                    pipelineLineVO.setDistance(distance);
                }
                List<FileVO> lineFile = fileServiceImpl.getFileByLineId(Lists.newArrayList(id));
                if (ObjectUtils.isNotEmpty(lineFile)) {
                    pipelineLineVO.setDrawing(fileURL + lineFile.get(0).getKeepName());
                }
                break;
            default:
                break;
        }
        // 管点信息不为空返回管点
        if (!Objects.isNull(pipelinePointVO)) {
            return ReturnMsg.consSuccess(pipelinePointVO);
        }
        // 管线信息不为空返回管线
        if (!Objects.isNull(pipelineLineVO)) {
            return ReturnMsg.consSuccess(pipelineLineVO);
        }
        //都为null说明查询不到数据
        return ReturnMsg.consFail("无法查询到相关信息");
    }

    /**
     * 清空管网数据
     *
     * @param type 管网类型：1管点数据   2管线数据
     * @return com.bcbim.common.response.vo.ReturnMsg
     * @author wxc
     * @date 2021/8/25  18:14
     */
    @PostMapping("/cleanPipeDate")
    public ReturnMsg cleanPipeDate(@RequestParam(required = true) String type) {
        // 参数校验
        try {
            ParamCheck.stringNotEmptyRegexpCheck(type, "^[1|2|3]$");
        } catch (ParamException e) {
            return ReturnMsg.consFail(ParamException.PARAMETER_ERROR);
        }
        // 没有type 的时候清空全部信息
        if ("3".equals(type)) {
            myReidsService.delete(AuthUtil.getPointToken(), AuthUtil.getLineToken());
        } else if ("1".equals(type)) {
            myReidsService.delete(AuthUtil.getPointToken());
        } else {
            myReidsService.delete(AuthUtil.getLineToken());
        }
        return ReturnMsg.consSuccess(Constant.SAVE_SUCCESS);
    }

    /**
     * @Description: 分页
     * @Param: list 数据集合
     * @Param: pageNum 页码
     * @Param: pageSize 每页数据记录数
     * @Return: List<?> 分页数据记录
     * @Author: haoshuai
     * @Date: 2021/8/24
     */
    private List<?> paging(List<?> list, int pageNum, int pageSize) {
        int total = list.size();
        int start = (pageNum - 1) * pageSize;
        int end = start + pageSize;
        return list.subList(start, total < end ? total : end);
    }


    /**
     * 获取全部管网信息(用于显示模型)
     *
     * @return ReturnMsg
     * @author wxc
     * @date 2021/8/27  9:15
     */
    @PostMapping("/listPipe")
    public ReturnMsg listPipe() {
        //查找全部管点管线
        Map<String, Object> map = pipeManagementService.getAllPipeList();
        return ReturnMsg.consSuccess(map);
    }

    /**
     * 获取集选中的管线数据,用于显示水波流向
     *
     * @return com.bcbim.common.response.vo.ReturnMsg
     * @author wxc
     * @date 2021/9/2  17:09
     */
    @PostMapping("/listPipeLineUseWater")
    public ReturnMsg listPipeLineUseWater() {
        // 获取管线集选数据
        JSONArray jsonArray = (JSONArray) myReidsService.get(AuthUtil.getLineToken());
        if (ObjectUtils.isEmpty(jsonArray)) {
            return ReturnMsg.consFail("集选中暂无数据！");
        }
        // 通过集选数据获取管线id
        List<String> lineIdList = new ArrayList<>();
        jsonArray.toJavaList(PipeListVO.class).forEach(obj -> lineIdList.add(obj.getId()));
        // 通过管线id集合查询数据,用于显示水波流向
        List<PipeLineListUseWaterVO> list = pipeManagementService.listPipeLineUseWater(lineIdList);
        // 计算两个点距离
        list.stream().filter(obj -> {
            return ObjectUtils.isNotEmpty(obj.getStartX()) && ObjectUtils.isNotEmpty(obj.getStartY())
                    && ObjectUtils.isNotEmpty(obj.getEndX()) && ObjectUtils.isNotEmpty(obj.getEndY());
        }).collect(Collectors.toList()).forEach(line -> {
            double distance = LngLonUtil.getDistanceMeter(Double.parseDouble(line.getStartX()),
                    Double.parseDouble(line.getStartY()),
                    Double.parseDouble(line.getEndX()),
                    Double.parseDouble(line.getEndY()), Ellipsoid.WGS84);
            line.setDistance(distance);
        });

        return ReturnMsg.consSuccess(list);

    }

    /**
     * 框选数据加入集选
     *
     * @return com.bcbim.common.response.vo.ReturnMsg
     * @author wxc
     * @date 2021/10/11
     */
    @PostMapping("/framePipe")
    public ReturnMsg framePipe(PipelineFrameSelectInput pipelineFrameSelectInput) {
        String regex = "\\d+(.\\d+)?";
        // 参数校验
        try {
            ParamCheck.stringNotEmptyRegexpCheck(pipelineFrameSelectInput.getStartX(), regex);
            ParamCheck.stringNotEmptyRegexpCheck(pipelineFrameSelectInput.getStartY(), regex);
            ParamCheck.stringNotEmptyRegexpCheck(pipelineFrameSelectInput.getEndX(), regex);
            ParamCheck.stringNotEmptyRegexpCheck(pipelineFrameSelectInput.getEndY(), regex);
        } catch (ParamException e) {
            return ReturnMsg.consFail(ParamException.PARAMETER_ERROR);
        }
        // 获取管点类型
        List<PipeListVO> pointList = pipeManagementService.listPointByCodes(pipelineFrameSelectInput);
        if (ObjectUtils.isNotEmpty(pointList)) {
            // 取redis中数据集合
            String token = AuthUtil.getPointToken();
            if (StringUtils.isEmpty(token)) {
                return ReturnMsg.consFail("查询失败，请重新登录。");
            }
            JSONArray jsonArray = (JSONArray) myReidsService.get(token);
            List<PipeListVO> cacheList = jsonArray == null ? null : jsonArray.toJavaList(PipeListVO.class);

            // 写入集合
            // 缓存中数据为null，则直接存入缓存
            // 缓存中存在数据，将数据去重后重新写入redis
            List<PipeListVO> list;
            if (ObjectUtils.isEmpty(cacheList)) {
                list = pointList;
            } else {
                list = MyListUtil.removeAll(pointList, cacheList);
                list.addAll(cacheList);
            }
            // 写入redis
            myReidsService.set(token, list, Constant.PERMISSION_EXPIRATION_TIME);
        }
        // 获取管线类型
        List<PipeListVO> lineList = pipeManagementService.listLineByCodes(pipelineFrameSelectInput);
        if (ObjectUtils.isNotEmpty(lineList)) {
            // 取redis中管线数据集合
            String lineToken = AuthUtil.getLineToken();
            if (StringUtils.isEmpty(lineToken)) {
                return ReturnMsg.consFail("查询失败，请重新登录。");
            }
            JSONArray lineJsonArray = (JSONArray) myReidsService.get(lineToken);
            List<PipeListVO> cacheListLine = null == lineJsonArray ? null : lineJsonArray.toJavaList(PipeListVO.class);

            // 写入集合
            // 若缓存中数据集合不为空, 则将查询集合和缓存集合去重后合并
            // 若缓存中数据集合为空, 则将查询结合作为结果集合
            List<PipeListVO> list;
            if (CollectionUtils.isNotEmpty(cacheListLine)) {
                list = MyListUtil.removeAll(lineList, cacheListLine);
                list.addAll(cacheListLine);
            } else {
                list = lineList;
            }

            // 写入redis
            myReidsService.set(lineToken, list, Constant.PERMISSION_EXPIRATION_TIME);
            return ReturnMsg.consSuccess(Constant.SAVE_SUCCESS);
        }
        return ReturnMsg.consSuccess(Constant.SAVE_SUCCESS);
    }

    @Translate
    @RequestMapping("/listPipelinePoints")
    public ReturnMsg listPipelinePoints(String[] pointIds) {
        if (pointIds.length <= 1) {
            ReturnMsg.consFail("单个管井，无法生成剖面图");
        }
        for (String id : pointIds) {
            try {
                ParamCheck.idCheck(id);
            } catch (ParamException e) {
                ReturnMsg.consFail(ParamException.PARAMETER_ERROR);
            }
        }
        //List<PipeLinePointsListVO> linePointsListVOS = pipeManagementService.listPipelinePoints(pointIds);
        Map<String, Object> linePointsListVOS = pipeManagementService.listPipelinePointsByPointIds(pointIds);
        if (ObjectUtils.isEmpty(linePointsListVOS)) {
            return ReturnMsg.consFail("所选管井中有不相邻管井，生成剖面图失败！");
        }
        TranslateHandle.translationData(linePointsListVOS.get("pipeLinePoint"));
        return ReturnMsg.consSuccess(linePointsListVOS);
    }

    @RequestMapping("/listPipePointByCode")
    public ReturnMsg listPipePointByCode(String code) {
        //查询所有管点数据
        List<PipeListCodeVO> listCode = pipelinePointServiceImpl.getPipelinePointByCode(code);
        return ReturnMsg.consSuccess(listCode);
    }
}
